﻿using Fast.ConfigureOptions;
using Fast.Reflection;
using Microsoft.Extensions.Configuration;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerUI;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Fast.Swagger
{
    /// <summary>
    /// swagger文档配置选项
    /// </summary>
    [SkipScan]
    internal class SwaggerDocumentSettingsOptions : IConfigureOptions<SwaggerDocumentSettingsOptions>
    {
        /// <summary>
        /// 是否启用授权
        /// </summary>
        public bool? EnableAuthorized { get; set; }
        /// <summary>
        /// 文档标题
        /// </summary>
        public string DocumentTitle { get; set; }

        /// <summary>
        /// 配置Swagger文档地址
        /// </summary>
        public string RoutePrefix { get; set; }

        /// <summary>
        /// 模型折叠深度
        /// </summary>
        public int? ModelsExpandDepth { get; set; }

        /// <summary>
        /// 文档展开设置
        /// </summary>
        public DocExpansion? DocExpansionState { get; set; }

        /// <summary>
        /// XML 描述文件
        /// </summary>
        public string[] XmlComments { get; set; }

        /// <summary>
        /// 文档组
        /// </summary>
        public SwaggerDoc SwaggerDocGroup { get; set; }

        /// <summary>
        /// 安全方案
        /// </summary>
        public SecurityDefinition SecurityDefinition { get; set; }

        /// <summary>
        /// 安全需求
        /// </summary>
        public SecurityRequirement SecurityRequirement { get; set; }

        /// <summary>
        /// 默认 swagger.json 路由模板
        /// </summary>
        public string RouteTemplate { get; set; }

        public void PostConfigure(SwaggerDocumentSettingsOptions options, IConfiguration configuration)
        {
            options.DocumentTitle ??= "Swagger Api Document";
            options.DocExpansionState ??= DocExpansion.List;
            options.ModelsExpandDepth ??= -1;

            // 加载项目注册和模块化/插件注释
            var frameworkPackageName = AssemblyHelper.GetAssemblyName(GetType());
            var projectXmlComments = App.Assemblies.Where(u => u.GetName().Name != frameworkPackageName).Select(t => t.GetName().Name);
            var externalXmlComments = App.ExternalAssemblies.Any() ? App.Settings.ExternalAssemblies.Select(u => u.EndsWith(".dll") ? u[0..^4] : u) : Array.Empty<string>();
            XmlComments ??= projectXmlComments.Concat(externalXmlComments).ToArray();


            //配置安全需求
            EnableAuthorized ??= true;
            if (EnableAuthorized.Value)
            {
                SecurityDefinition ??= new SecurityDefinition()
                {
                    Name = "Bearer",
                    OpenApiSecurityScheme = new OpenApiSecurityScheme
                    {
                        Scheme = "Bearer",
                        BearerFormat = "JWT",
                        In = ParameterLocation.Header,
                        Name = "Authorization",
                        Type = SecuritySchemeType.ApiKey
                    }
                };
                options.SecurityRequirement ??= new SecurityRequirement
                {
                    OpenApiSecurityScheme = new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme }
                    },
                    Accesses = Array.Empty<string>()
                };
            }

            //配置分组
            if ((SwaggerDocGroup == null || SwaggerDocGroup.Count == 0))
            {
                SwaggerDocGroup = new SwaggerDoc();
            }

            var docGroups = SwaggerDocGroup.ToList();
            if (!SwaggerDocGroup.ContainsKey(SwaggerDoc.DefaultName))
            {
                docGroups.Insert(0, new KeyValuePair<string, OpenApiInfo>(SwaggerDoc.DefaultName, new SwaggerDoc().Default()));
            }
            SwaggerDocGroup.Clear();
            docGroups.ForEach(item => SwaggerDocGroup.TryAdd(item.Key, item.Value));

            RouteTemplate ??= "swagger/{documentName}/swagger.json";
        }
    }
}
